#Kyle Bakken, Chelsea Evans, Adam Lamb - Group 6
#CS419-400
#Description: This program provides a command line interface
#To be used by the advisor in order to view and/or cancel upcoming appointments
#Input: 
#     1. Program processes UP/DOWN arrow keys for menu navigation, numeric input from 0-9, and newline characters
#     2. sqlhandler.py provides database information input for both single, and multiple selections.
#Output: This program will output an Appointment object to
#     1. The SQL py script 
#     2. The StringFilter.py script

from time import sleep
import curses
import os
import sqlhandler
import string
import StringFilter

##Initialise Curses Screen Parameters
screen = curses.initscr()
curses.noecho()
curses.cbreak()
curses.start_color()
screen.keypad(1)
curses.init_pair(1,curses.COLOR_BLACK, curses.COLOR_WHITE)
highlight = curses.color_pair(1)
normal = curses.A_NORMAL
clearData = False
SelectedNumber = ""

counselorName = "Kyle C. Bakken\n"
originEmail = "do.not.reply@engr.orst.edu\n"
sentDate = "Thursday, November 15, 2012 10:11\n"
advisorEmail = "bakkenk@onid.oregonstate.edu\n"
subject = "Advising Signup Cancellation\n"

MENU = "menu"
QUERY = "query"
EXIT = "exitmenu"

##Menu array for managing selections within the curses screen
menuArray = {
  'title': "Advising System", 'type': MENU, 'subtitle': "Manage Appointments: Use the Up/Down Arrows to navigate",
  'options': [
    { 'title': "View Appointments", 'type': QUERY, 'query': 'viewappt' },
  ]
}

##Removes specified characters from the string overall
def removeAllBad(inputString):
  parsedString = inputString
  parsedString = str(parsedString).replace(']', '')
  parsedString = str(parsedString).replace('[', '')
  parsedString = str(parsedString).replace("'", "")
  parsedString = str(parsedString).strip('\n')
  parsedString = str(parsedString).strip('\r')
  return parsedString

##Remove the return carriage if it exists, and any empty space from the front and back of string.
def removeBad(inputString):
  foundCarriage = False
  goodChar = False
  parseString = ""
  parseString = inputString
  while goodChar == False:
    ##If 'r' character encountered, delete it and the backslash.
    if parseString[-1] == 'r' and foundCarriage == False:
      parseString = parseString[:-1]
      parseString = parseString[:-1]
      foundCarriage = True
    ##if parseString[-1].isspace() == True:
      ##parseString = parseString[:-1]
    else:
      goodChar = True
  ##lstrip removes all empty spaces from the beginning of the string
  parseString = parseString.lstrip()
  return parseString

##Returns string information from the database to be parsed and sent to an email filter.
def cancelAppt(cancelNumber):
  myString = ""
  myString = sqlhandler.CLICancel(cancelNumber)
  return myString

##Returns query of information concerning recent appointments  
def queryAppt():
  myString = ""
  myString = sqlhandler.DBSelect()
  return myString

# This function displays the appropriate menu and returns the option selected
def updateCLI(menu, isRun, parent):
  triggerDisplay = False
  displayAppointments = isRun
  CLIString = ""
  if parent is None:
    lastoption = "Exit"
  else:
    lastoption = "Return to %s menu" % parent['title']
 
  numLines = len(menu['options'])
  numEntry = 0
  pos=0
  oldpos=None
  input = None
  endLoop = False
 
  # Loop until return key is pressed
  while not endLoop:
    ##TITLE DISPLAY
    ##If the cursor position has changed, update the screen
    if pos != oldpos:
      oldpos = pos
      screen.border(0)
      ##Display Title and Subtitle
      screen.addstr(2,2, menu['title'], curses.A_STANDOUT)
      screen.addstr(4,2, menu['subtitle'], curses.A_BOLD)
      
	  ##MENU DISPLAY
      ##Display all the menu items, showing the 'pos' item highlighted
      for index in range(numLines):
        textstyle = normal
        if pos==index:
          textstyle = highlight
        screen.addstr(5+index,4, "%d - %s" % (index+1, menu['options'][index]['title']), textstyle)
      # Now display Exit/Return at bottom of menu
      textstyle = normal
      if pos==numLines:
        textstyle = highlight
      if not displayAppointments:
        screen.addstr(5+numLines,4, "%d - %s" % (numLines+1, lastoption), textstyle)
      screen.refresh()
      # finished updating screen
    CLINum = 0
  
  
    ##INPUT HANDLING
    ##Get the user input as a single character
    input = screen.getch()
    #Get use input
    if input >= ord('0') and input <= ord('9'):
      ##Get the keypress value
      numEntry = input - ord('0')
      ##Used for building multi-digit ints via command line.
      CLIString += str(numEntry)
      SelectedNumber = str(CLIString)
    ##Check ascii value for down arrow    
    elif input == 258:
      if pos < numLines:
        pos += 1
      else: pos = 0
    ##Check ascii value for up arrow    
    elif input == 259:
      if pos > 0:
        pos += -1
      else: 
        pos = numLines
    ##If return entered, handle numeric input, and update screen.    
    elif input == ord('\n'):
      screen.clear()
      if CLIString != "":
        try: 
          CLINum = int(CLIString)
        except ValueError:
          CLINum = 0			  
      if CLINum > 0 and displayAppointments:
        screen.clear()
        cancelString = ""
        cancelString = sqlhandler.CLICancel(CLINum)
        if len(cancelString) < 1:
          screen.addstr(13, 4, "Appointment not found, cancellation failed.")
          screen.addstr(16, 4, "Press return go back to upcoming appointment view.")
        else:
          screen.addstr(9, 4, "Are you sure you would like to cancel this appointment? <y/n>")
          ##cancelString = removeAllBad(cancelString)
          screen.addstr(13, 4, "Appointment: %s" % cancelString)
          ##Get the user input as a single character
          cancelInput = screen.getch()
          if cancelInput == ord('y'):
            screen.clear()
            screen.addstr(13, 4, "Cancelling: %s" % cancelString)
            screen.addstr(16, 4, "Press return go back to upcoming appointment view.")
            sqlhandler.doCancel(CLINum)
            dateString = ""

            cancelXML = ""
            parsedString = removeAllBad(cancelString)
            ##Parse the data by comma and store code each substring into an xml string.
            cancelList = str(parsedString).split(',')
            m = 0
            for data in cancelList:
              if m == 0:
                stringData = str(data)
                stringData = removeBad(stringData)
                addData = "<name>" + str(stringData) + "</name>"
                cancelXML = addData
              if m == 1:
                stringData = str(data)
                stringData = removeBad(stringData)
                addData = "<email>" + str(stringData) + "</email>"
                cancelXML += addData
              if m == 2:
                stringData = str(data)
                stringData = removeBad(stringData)
                addData = "<day>" + str(stringData) + "</day>"
            	cancelXML += addData
              if m == 3:
                dateString = str(data) + ","
              if m == 4:
                stringData = str(data)
                stringData = "" + dateString + data
                stringData = removeBad(stringData)
                addData = "<date>" + str(stringData) + "</date>"
                cancelXML += addData
              if m == 5:
                stringData = str(data)
                stringData = removeBad(stringData)
                addData = "<start>" + str(stringData) + "</start>"
                cancelXML += addData
              if m == 6:
                stringData = str(data)
                stringData = removeBad(stringData)
                addData = "<end>" + str(stringData) + "</end>"
                cancelXML += addData
              m = m+1

            addCounselor = "<cname>" + str(counselorName) + "</cname>"
            cancelXML += addCounselor
            addCounselor = "<orgmail>" + str(originEmail) + "</orgmail>"
            cancelXML += addCounselor
            addCounselor = "<sentdate>" + str(sentDate) + "</sentdate>"
            cancelXML += addCounselor
            addCounselor = "<advisoremail>" + str(advisorEmail) + "</advisoremail>"
            cancelXML += addCounselor
            addCounselor = "<mailsubject>" + str(subject) + "</mailsubject>"
            cancelXML += addCounselor
              
            ##screen.addstr(13, 4, cancelXML)
            ##Send embedded string to the string filter, which parses the information into an appointment object.
            StringFilter.sendMessage(cancelXML)
          else:
            screen.clear()
            screen.addstr(13, 4, "Cancellation Aborted")
            screen.addstr(16, 4, "Press return go back to upcoming appointment view.")
      ##End the loop if return key entered
      endLoop = True
    if pos != numLines:
      screen.addstr(9, 4, "To specify an appointment to cancel, type the appointment's 'ID' number, and press enter.")
      screen.addstr("\n")
      screen.addstr("       Selection: %s" % CLIString)
  return pos
 
def runTerminal(menu, parent=None):
  numLines = len(menu['options'])
  exitmenu = False
  ##Main functional curses Loop, runs until exit is specified.
  while not exitmenu: #Loop until the user exits the menu 
    ##Wait for input
    cursor = updateCLI(menu, False, parent)
    
    if cursor == numLines:
        exitmenu = True
    
    ##If command selected, execute that command.
    elif menu['options'][cursor]['type'] == QUERY:
      ##Import and parse string for bad input
      dataString = str(queryAppt())
      dataString = removeAllBad(dataString)
      ##Create list from imported string
      dataList = dataString.split("$")
      ##Save the screen
      curses.def_prog_mode()
      ##If a query is selected, run the query
      if menu['options'][cursor]['query'] == 'viewappt':
        i = 0
        ##Print informatin for queried appointments
        for data in dataList:
          screen.addstr("\n")
          individualData = data.split(",")
          j = 0
          addData = ""
          ##Print organized information for the appointment
          for appointmentData in individualData:
            highlightLine = False
            if i == 0:
              addData = "                          "
              if j == 0:
                appointmentData = removeBad(appointmentData)
                if highlightLine == True:
                  textStyle = highlight
                else:
				  textStyle = normal
                addData = screen.addstr("      ID: %s   " % (appointmentData), textStyle)
              if j == 1:
                appointmentData = removeBad(appointmentData)
                if highlightLine == True:
                  textStyle = highlight
                else:
				  textStyle = normal
                addData = screen.addstr("Name: %s   " % (appointmentData), textStyle)
              if j == 6:
                appointmentData = removeBad(appointmentData)
                if highlightLine == True:
                  textStyle = highlight
                else:
				  textStyle = normal
                addData = screen.addstr("Appointment Time: %s" % (appointmentData), textStyle)
              j = j+1
            ##Remove offset for lack of comma in the beginning of the list.
            else:
              addData = ""
              if j == 1:
                appointmentData = removeBad(appointmentData)
                if highlightLine == True:
                  textStyle = highlight
                else:
				  textStyle = normal
                addData = screen.addstr("      ID: %s   " % (appointmentData), textStyle)
              if j == 2:
                appointmentData = removeBad(appointmentData)
                if highlightLine == True:
                  textStyle = highlight
                else:
				  textStyle = normal
                addData = screen.addstr("Name: %s   " % (appointmentData), textStyle)
              if j == 7:
                appointmentData = removeBad(appointmentData)
                if highlightLine == True:
                  textStyle = highlight
                else:
				  textStyle = normal
                addData = screen.addstr("Appointment Time: %s" % (appointmentData), textStyle)
              j = j+1 
          i = i+1			
        screen.refresh()
        getData = updateCLI(menu, True, parent)
    elif menu['options'][cursor]['type'] == EXITMENU:
          exitmenu = True

#Run Program
runTerminal(menuArray)
curses.endwin() #VITAL! This closes out the menu system and returns you to the bash prompt.
os.system('clear')